/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cn.xo68.ide.plugin.common.swing.treetable;

import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.renderer.DefaultTreeRenderer;
import org.jdesktop.swingx.treetable.DefaultMutableTreeTableNode;
import org.jdesktop.swingx.treetable.TreeTableNode;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.TreePath;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 *
 * @author Santhosh Kumr T - santhosh@in.fiorano.com
 */
public class CheckTreeTableManager extends MouseAdapter implements TreeSelectionListener {

    private CheckTreeSelectionModel selectionModel;
    private JXTreeTable treetable;
    private JTree tree;
    int hotspot = new JCheckBox().getPreferredSize().width;



    public CheckTreeTableManager(JXTreeTable treeTable) {
        this.treetable = treeTable;
        this.tree = (JTree) treeTable.getCellRenderer(0, 0);
        selectionModel = new CheckTreeSelectionModel(tree.getModel());
        tree.setCellRenderer(new DefaultTreeRenderer(new CheckTreeCellProvider(selectionModel)));
        treeTable.addMouseListener(this);

        selectionModel.addTreeSelectionListener(this);

        initSelected();

    }

    /**
     * 初始化选中状态
     */
    public void initSelected(){
        DefaultMutableTreeTableNode rootNode=getRootNode();
        selectionModel.removeTreeSelectionListener(this);
        try{
            initSelected(rootNode, false);
        }finally {
            selectionModel.addTreeSelectionListener(this);
            treetable.repaint();
        }
        //checkStateChanged();
    }

    /**
     * 选中节点
     * @param node
     * @param check
     * @param repaint
     */
    private void checkNode(DefaultMutableTreeTableNode node, boolean check, boolean repaint){
        if(repaint){
            selectionModel.removeTreeSelectionListener(this);
        }
        if(node.getUserObject() instanceof CheckContextProvider){
            TreePath path = new TreePath(getNodePath(node));
            boolean selected = selectionModel.isPathSelected(path, true);
            if (selected && !check) {
                selectionModel.removeSelectionPath(path);
            } else if(!selected && check) {
                selectionModel.addSelectionPath(path);
            }
        }
        if(repaint){
            selectionModel.addTreeSelectionListener(this);
            treetable.repaint();
        }
    }

    private void initSelected(DefaultMutableTreeTableNode node, boolean repaint){
        if(node.getUserObject() instanceof CheckContextProvider){
            CheckContextProvider contextProvider= (CheckContextProvider) node.getUserObject();
            checkNode(node, contextProvider.isChecked(), repaint);
        }
        for(int i=0; i < node.getChildCount(); i++){
            initSelected((DefaultMutableTreeTableNode) node.getChildAt(i),repaint);
        }
    }

    /**
     * 根节点
     * @return
     */
    public DefaultMutableTreeTableNode getRootNode(){
        Object obj=tree.getModel().getRoot();
        if(obj instanceof DefaultMutableTreeTableNode){
            DefaultMutableTreeTableNode node = (DefaultMutableTreeTableNode) obj;
            return node;
        }
        return null;
    }

    /**
     * 返回节点路径，如：根节点，父节点，自己
     * @param node
     * @return
     */
    public TreeTableNode[] getNodePath(DefaultMutableTreeTableNode node){
        List<TreeTableNode> nodes= new LinkedList<>();
        nodes.add(node);
        DefaultMutableTreeTableNode tempNode= (DefaultMutableTreeTableNode) node.getParent();
        while (tempNode != null){
            nodes.add(tempNode);
            tempNode= (DefaultMutableTreeTableNode) tempNode.getParent();
        }
        Collections.reverse(nodes);

        return nodes.toArray(new TreeTableNode[0]);
    }

    public void selectedAll(boolean selected){
        DefaultMutableTreeTableNode rootNode=getRootNode();
        selectionModel.removeTreeSelectionListener(this);
        try{
            selectedAll(rootNode, selected, false);
        }finally {
            selectionModel.addTreeSelectionListener(this);
            treetable.repaint();
        }
    }

    /**
     * 全选、全不还
     * @param node
     * @param selected
     */
    public void selectedAll(DefaultMutableTreeTableNode node, boolean selected, boolean repaint){
        if(node.getUserObject() instanceof CheckContextProvider){
            ((CheckContextProvider) node.getUserObject()).setChecked(selected);
            checkNode(node, selected, repaint);
        }
        for(int i=0; i < node.getChildCount(); i++){
            selectedAll((DefaultMutableTreeTableNode) node.getChildAt(i), selected, repaint);
        }
        //checkStateChanged();
    }

    @Override
    public void mouseClicked(MouseEvent me) {
        TreePath path = tree.getPathForLocation(me.getX(), me.getY());
        if (path == null) {
            return;
        }
        if (me.getX() > tree.getPathBounds(path).x + hotspot) {
            return;
        }

        boolean selected = selectionModel.isPathSelected(path, true);
        selectionModel.removeTreeSelectionListener(this);

        try {
            if (selected) {
                selectionModel.removeSelectionPath(path);
            } else {
                selectionModel.addSelectionPath(path);
            }
        } finally {
            selectionModel.addTreeSelectionListener(this);
            treetable.repaint();
        }
        //checkStateChanged();
    }

    public CheckTreeSelectionModel getSelectionModel() {
        return selectionModel;
    }

    public void valueChanged(TreeSelectionEvent e) {
        //checkStateChanged();
    }
}